{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "638a7203",
   "metadata": {},
   "source": [
    "# 什么是ufuncs？\n",
    "ufuncs是 \"通用函数 \"的缩写，它们是对ndarray对象进行操作的NumPy函数。\n",
    "\n",
    "# 为什么使用ufuncs？\n",
    "ufuncs用于在NumPy中实现矢量化，这比在元素上迭代快得多。\n",
    "\n",
    "它们还提供了广播和额外的方法，如 reduce, accumulate 等，对计算很有帮助。\n",
    "\n",
    "ufuncs也接受额外的参数，比如。\n",
    "\n",
    "where 布尔数组或条件，定义操作发生的位置。\n",
    "\n",
    "dtype 定义了元素的返回类型。\n",
    "\n",
    "out 输出数组，返回值应该被复制到这里。\n",
    "\n",
    "# 什么是矢量化？\n",
    "将迭代语句转换为基于矢量的操作称为矢量化。\n",
    "\n",
    "它的速度更快，因为现代的CPU对这种操作进行了优化。\n",
    "\n",
    "两个列表的元素求和\n",
    "\n",
    "list 1: [1, 2, 3, 4]\n",
    "\n",
    "list 2: [4, 5, 6, 7]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e4f8b2fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5, 7, 9, 11]\n"
     ]
    }
   ],
   "source": [
    "# 一种方法是对两个列表进行迭代，然后对每个元素求和。\n",
    "x = [1, 2, 3, 4]\n",
    "y = [4, 5, 6, 7]\n",
    "z = []\n",
    "\n",
    "for i, j in zip(x, y):\n",
    "  z.append(i + j)\n",
    "print(z)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3cd8882e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 5  7  9 11]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "z = np.add(x, y)\n",
    "\n",
    "print(z)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9b30825",
   "metadata": {},
   "source": [
    "# 简单的算术\n",
    "你可以在NumPy数组之间直接使用算术运算符+ - * /，但本节讨论的是相同的扩展，我们的函数可以接受任何类似数组的对象，如列表、图元等，并有条件地执行算术。\n",
    "\n",
    "有条件的算术：意味着我们可以定义算术操作应该发生的条件。\n",
    "\n",
    "所有讨论的算术函数都有一个where参数，我们可以在其中指定该条件。\n",
    "\n",
    "## 加法\n",
    "add()函数将两个数组的内容相加，并在一个新数组中返回结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7ace30f4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[30 32 34 36 38 40]\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 11, 12, 13, 14, 15])\n",
    "arr2 = np.array([20, 21, 22, 23, 24, 25])\n",
    "\n",
    "newarr = np.add(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e1746fe",
   "metadata": {},
   "source": [
    "## 减法\n",
    "subtract()函数用一个数组的值减去另一个数组的值，并在一个新的数组中返回结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1910dea8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-10  -1   8  17  26  35]\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 20, 30, 40, 50, 60])\n",
    "arr2 = np.array([20, 21, 22, 23, 24, 25])\n",
    "\n",
    "newarr = np.subtract(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ce8e36a",
   "metadata": {},
   "source": [
    "## 乘法\n",
    "multiply()函数将一个数组的值与另一个数组的值相乘，并将结果返回到一个新数组中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "406c659b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 200  420  660  920 1200 1500]\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 20, 30, 40, 50, 60])\n",
    "arr2 = np.array([20, 21, 22, 23, 24, 25])\n",
    "\n",
    "newarr = np.multiply(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d0274b5",
   "metadata": {},
   "source": [
    "## 除法\n",
    "divide()函数将一个数组的值与另一个数组的值相除，并将结果返回到一个新的数组中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "69da3a5d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 3.33333333  4.          3.          5.         25.          1.81818182]\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 20, 30, 40, 50, 60])\n",
    "arr2 = np.array([3, 5, 10, 8, 2, 33])\n",
    "\n",
    "newarr = np.divide(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e54dd8c8",
   "metadata": {},
   "source": [
    "## 幂\n",
    "power()函数将第一个数组中的数值上升到第二个数组中数值的幂，并将结果返回到一个新的数组中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7925d26d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[      1000    3200000  729000000 -520093696       2500          0]\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 20, 30, 40, 50, 60])\n",
    "arr2 = np.array([3, 5, 6, 8, 2, 33])\n",
    "\n",
    "newarr = np.power(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31c85aaf",
   "metadata": {},
   "source": [
    "## 余数\n",
    "mod()和remainder()函数都返回第一个数组中的数值对应于第二个数组中的数值的余数，并在一个新的数组中返回结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b7063ac0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1  6  3  0  0 27]\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 20, 30, 40, 50, 60])\n",
    "arr2 = np.array([3, 7, 9, 8, 2, 33])\n",
    "\n",
    "newarr = np.mod(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d87306c1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1  6  3  0  0 27]\n"
     ]
    }
   ],
   "source": [
    "newarr = np.remainder(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3a892cf",
   "metadata": {},
   "source": [
    "## 商和余数\n",
    "divmod()函数同时返回商和余数。返回值是两个数组，第一个数组包含商，第二个数组包含余数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "47ce15fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([ 3,  2,  3,  5, 25,  1], dtype=int32), array([ 1,  6,  3,  0,  0, 27], dtype=int32))\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([10, 20, 30, 40, 50, 60])\n",
    "arr2 = np.array([3, 7, 9, 8, 2, 33])\n",
    "\n",
    "newarr = np.divmod(arr1, arr2)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ed7e631",
   "metadata": {},
   "source": [
    "## 绝对值\n",
    "absolute()和abs()函数都是做同样的绝对运算元素，但我们应该使用absolute()来避免与python内置的math.abs()相混淆"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "aea66389",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 1 2 3 4]\n"
     ]
    }
   ],
   "source": [
    "arr = np.array([-1, -2, 1, 2, 3, -4])\n",
    "\n",
    "newarr = np.absolute(arr)\n",
    "\n",
    "print(newarr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1a97489",
   "metadata": {},
   "source": [
    "# 四舍五入小数\n",
    "在NumPy中主要有五种四舍五入小数的方法。\n",
    "\n",
    "截断\n",
    "\n",
    "固定\n",
    "\n",
    "四舍五入\n",
    "\n",
    "下限\n",
    "\n",
    "上限"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "454bce1c",
   "metadata": {},
   "source": [
    "## 截断\n",
    "去掉小数，并返回最接近零的浮点数。使用 trunc() 和 fix() 函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "fed7095e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-3.  3.]\n"
     ]
    }
   ],
   "source": [
    "arr = np.trunc([-3.1666, 3.6667])\n",
    "\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "12fa00db",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-3.  3.]\n"
     ]
    }
   ],
   "source": [
    "arr = np.fix([-3.1666, 3.6667])\n",
    "\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f50f1699",
   "metadata": {},
   "source": [
    "## 四舍五入\n",
    "around()函数将前面的数字或小数点增加1，如果>=5，则不做任何操作。\n",
    "\n",
    "例如，四舍五入到小数点后1位，3.16666就是3.2。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "93c9f157",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.17\n"
     ]
    }
   ],
   "source": [
    "arr = np.around(3.1666, 2)\n",
    "\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab79716c",
   "metadata": {},
   "source": [
    "## 下限\n",
    "floor()函数将小数四舍五入到最接近的小数。\n",
    "\n",
    "例如，3.166的地板是3。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "032f6824",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-4.  3.]\n"
     ]
    }
   ],
   "source": [
    "arr = np.floor([-3.1666, 3.6667])\n",
    "\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ba57356",
   "metadata": {},
   "source": [
    "## 上限\n",
    "ceil()函数将小数四舍五入到最接近的大整数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "6e0e8749",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-3.  4.]\n"
     ]
    }
   ],
   "source": [
    "arr = np.ceil([-3.1666, 3.6667])\n",
    "\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9e1790a",
   "metadata": {},
   "source": [
    "# 对数\n",
    "NumPy提供了以2、e和10为基数的日志函数。\n",
    "\n",
    "我们还将探索如何通过创建一个自定义的ufunc来获取任何进制的对数。\n",
    "\n",
    "如果不能计算对数，所有的对数函数都会在元素中放置-inf或inf。\n",
    "\n",
    "## 基数为2的对数\n",
    "使用log2()函数来进行以2为底的对数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "cb7104b2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4 5 6 7 8 9]\n",
      "[0.         1.         1.5849625  2.         2.32192809 2.5849625\n",
      " 2.80735492 3.         3.169925  ]\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(1, 10)\n",
    "print(arr)\n",
    "print(np.log2(arr))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21863254",
   "metadata": {},
   "source": [
    "## 基数为10的对数\n",
    "使用log10()函数来进行以10为底的对数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "59158d21",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4 5 6 7 8 9]\n",
      "[0.         0.30103    0.47712125 0.60205999 0.69897    0.77815125\n",
      " 0.84509804 0.90308999 0.95424251]\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(1, 10)\n",
    "print(arr)\n",
    "print(np.log10(arr))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5dd9256d",
   "metadata": {},
   "source": [
    "## 自然对数,基数为e的对数\n",
    "使用log()函数来进行以e为底的对数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "44ae96d8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3 4 5 6 7 8 9]\n",
      "[0.         0.69314718 1.09861229 1.38629436 1.60943791 1.79175947\n",
      " 1.94591015 2.07944154 2.19722458]\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(1, 10)\n",
    "print(arr)\n",
    "print(np.log(arr))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5166729",
   "metadata": {},
   "source": [
    "## 任意基数下的对数\n",
    "NumPy没有提供任何函数来记录任何基数的日志，所以我们可以使用frompyfunc()函数和内置的函数math.log()，有两个输入参数和一个输出参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "8aa1fc6b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.7005483074552052\n"
     ]
    }
   ],
   "source": [
    "from math import log\n",
    "\n",
    "nplog = np.frompyfunc(log, 2, 1)\n",
    "\n",
    "print(nplog(100, 15))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fccdfc31",
   "metadata": {},
   "source": [
    "# 创建你自己的ufunc\n",
    "## 如何创建你自己的 ufunc\n",
    "要创建你自己的ufunc，你必须定义一个函数，就像在Python中定义普通函数一样，然后用frompyfunc()方法把它添加到你的NumPy ufunc库。\n",
    "\n",
    "frompyfunc()方法接受以下参数。\n",
    "\n",
    "function - 该函数的名称。\n",
    "inputs - 输入参数的数量（数组）。\n",
    "outputs - 输出数组的数量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "87f1b11f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6 8 10 12]\n"
     ]
    }
   ],
   "source": [
    "def myadd(x, y):\n",
    "  return x+y\n",
    "\n",
    "myadd = np.frompyfunc(myadd, 2, 1)\n",
    "\n",
    "print(myadd([1, 2, 3, 4], [5, 6, 7, 8]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c242116f",
   "metadata": {},
   "source": [
    "## 检查一个函数是否是ufunc\n",
    "检查一个函数的类型，以检查它是否是ufunc。\n",
    "\n",
    "ufunc应该返回<class 'numpy.ufunc'>。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "4052e095",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ufunc'>\n"
     ]
    }
   ],
   "source": [
    "print(type(np.add))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "cd651479",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'function'>\n"
     ]
    }
   ],
   "source": [
    "# 如果它不是一个ufunc，它将返回另一种类型，就像这个内置的NumPy函数，用于连接两个或多个数组\n",
    "print(type(np.concatenate))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "0d8e879c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "add is ufunc\n"
     ]
    }
   ],
   "source": [
    "# 要在if语句中测试函数是否是ufunc，可以使用numpy.ufunc值\n",
    "if type(np.add) == np.ufunc:\n",
    "  print('add is ufunc')\n",
    "else:\n",
    "  print('add is not ufunc')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
